package com.ooolong.expression;

import com.ooolong.expression.function.Function;
import com.ooolong.expression.operator.Operator;

public abstract class OObject {
	public static final int BOOLEAN = 0;
	public static final int BYTE = 1;
	public static final int SHORT = 2;
	public static final int INTEGER = 3;
	public static final int LONG = 4;
	public static final int FLOAT = 5;
	public static final int DOUBLE = 6;

	public static final int STRING = 10;

	public static final int ADD = 20;
	public static final int SUBTRACT = 21;
	public static final int MULTIPLY = 22;
	public static final int DIVIDE = 23;
	public static final int REMAIND = 24;

	public static final int EQUAL = 30;
	public static final int GREATERTAHN = 31;
	public static final int LESSTHAN = 32;
	public static final int NOTEQUAL = 33;
	public static final int GREATERTAHN_OR_EQUAL = 34;
	public static final int LESSTHAN_OR_EQUAL = 35;

	public static final int LEFT_PARENTHESIS = 40;
	public static final int RIGHT_PARENTHESIS = 41;
	public static final int LEFT_SQUARE_BRACKET = 42;
	public static final int RIGHT_SQUARE_BRACKET = 43;
	public static final int LEFT_CURLY_BRACE = 44;
	public static final int RIGHT_CURLY_BRACE = 45;

	public static final int FUNCTION_MATH_ABS = 60;
	public static final int FUNCTION_MATH_ACOS = 61;
	public static final int FUNCTION_MATH_ASIN = 62;
	public static final int FUNCTION_MATH_ATAN = 63;
	public static final int FUNCTION_MATH_ATAN2 = 64;
	public static final int FUNCTION_MATH_CEIL = 65;
	public static final int FUNCTION_MATH_COS = 66;
	public static final int FUNCTION_MATH_EXP = 67;
	public static final int FUNCTION_MATH_FLOOR = 68;
	public static final int FUNCTION_MATH_IEEEREMAINDER = 69;
	public static final int FUNCTION_MATH_LOG = 70;
	public static final int FUNCTION_MATH_MAX = 71;
	public static final int FUNCTION_MATH_MIN = 72;
	public static final int FUNCTION_MATH_POW = 73;
	public static final int FUNCTION_MATH_RANDOM = 74;
	public static final int FUNCTION_MATH_RINT = 75;
	public static final int FUNCTION_MATH_ROUND = 76;
	public static final int FUNCTION_MATH_SIN = 77;
	public static final int FUNCTION_MATH_SQRT = 78;
	public static final int FUNCTION_MATH_TAN = 79;
	public static final int FUNCTION_MATH_TODEGREE = 80;
	public static final int FUNCTION_MATH_TORADIANS = 81;

	public static final int FUNCTION_STRING_COMPARETO = 100;
	public static final int FUNCTION_STRING_COMPARETOIGNORECASE = 101;
	public static final int FUNCTION_STRING_CONCAT = 102;
	public static final int FUNCTION_STRING_ENDWITH = 103;
	public static final int FUNCTION_STRING_EQUALS = 104;
	public static final int FUNCTION_STRING_EQUALSIGNORECASE = 105;
	public static final int FUNCTION_STRING_EVAL = 106;
	public static final int FUNCTION_STRING_INDEXOF = 107;
	public static final int FUNCTION_STRING_LASTINDEXOF = 108;
	public static final int FUNCTION_STRING_LENGTH = 109;
	public static final int FUNCTION_STRING_REPLACE = 110;
	public static final int FUNCTION_STRING_STARTWITH = 111;
	public static final int FUNCTION_STRING_SUBSTRING = 112;
	public static final int FUNCTION_STRING_TOLOWERCASE = 113;
	public static final int FUNCTION_STRING_TOUPPERCASE = 114;
	public static final int FUNCTION_STRING_TRIM = 115;

	public static final int VARIABLE = 200;

	protected Object obj;
	protected int type;
	protected String name;

	public static final OObject newInstance(Object obj) {
		if (obj instanceof Boolean) {
			return new OBoolean(obj);
		} else if (obj instanceof Number) {
			return new ONumber(obj);
		} else if (obj instanceof String) {
			return new OString(obj);
		} else if (obj instanceof FunctionName) {
			return Function.createFunction(((FunctionName) obj).getName());
		} else if (obj instanceof OperatorSymbol) {
			return Operator.createOperator(((OperatorSymbol) obj).getSymbol());
		} else if (obj instanceof ClosedPathSymbol) {
			return new OClosedPathSymbol(((ClosedPathSymbol) obj).getSymbol());
		}
		return null;
	}

	public static FunctionName newFunctionName(String functionName) {
		return new FunctionName(functionName);
	}

	public static OperatorSymbol newOperatorSymbol(String symbol) {
		return new OperatorSymbol(symbol);
	}

	public static ClosedPathSymbol newClosedPathSymbol(char symbol) {
		return new ClosedPathSymbol(symbol);
	}

	protected OObject() {
	}

	public String toString() {
		return this.obj.toString();
	}

	public Object getValue() {
		return this.obj;
	}

	public int getType() {
		return this.type;
	}

	public boolean isInteger() {
		if (this.type == SHORT || this.type == INTEGER || this.type == LONG) {
			return true;
		}
		return false;
	}

	public boolean isFloat() {
		if (this.type == FLOAT || this.type == DOUBLE) {
			return true;
		}
		return false;
	}

	public boolean isNumber() {
		return this.isInteger() || this.isFloat();
	}

	public Double toDouble() {
		if (!this.isNumber()) {
			return null;
		}
		return new Double(((Number) obj).doubleValue());
	}

	public Long toLong() {
		if (!this.isNumber()) {
			return null;
		}
		return new Long(((Number) obj).longValue());
	}

	public String getString() {
		return this.obj.toString();
	}

	public static class FunctionName {
		private String name;

		public FunctionName(String name) {
			this.name = name;
		}

		public String getName() {
			return this.name;
		}
	}

	public static class OperatorSymbol {
		private String symbol;

		public OperatorSymbol(String symbol) {
			this.symbol = symbol;
		}

		public String getSymbol() {
			return this.symbol;
		}
	}

	public static class ClosedPathSymbol {
		private char symbol;

		public ClosedPathSymbol(char symbol) {
			this.symbol = symbol;
		}

		public char getSymbol() {
			return this.symbol;
		}
	}

	abstract public OObject execute(OObject[] args) throws ExpressionException;
}
